package com.mx.ymate.modbus.impl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: xujianpeng
 * @Date: 2025/11/10
 * @Description: Modbus寄存器缓存工具类
 * key = 寄存器地址，value = 16位寄存器数据
 */
public class SlaveModbusCache {

    /**
     * slaveId -> 寄存器Map
     */
    private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Integer, Integer>> SLAVE_MAP = new ConcurrentHashMap<>();

    /**
     * 获取 slave 对应的寄存器Map，不存在就创建
     */
    private static ConcurrentHashMap<Integer, Integer> getRegisterMap(int slaveId) {
        return SLAVE_MAP.computeIfAbsent(slaveId, k -> new ConcurrentHashMap<>());
    }

    /**
     * 写单个寄存器
     */
    public static void write(int slaveId, int address, int value) {
        getRegisterMap(slaveId).put(address, value & 0xFFFF);
    }

    /**
     * 写多个寄存器，ByteBuf版本
     */
    public static void write(int slaveId, int startAddress, ByteBuf buf) {
        byte[] data = new byte[buf.readableBytes()];
        buf.readBytes(data);
        write(slaveId, startAddress, data);
    }

    /**
     * 写多个寄存器，byte[]版本
     */
    public static void write(int slaveId, int startAddress, byte[] data) {
        Map<Integer, Integer> map = getRegisterMap(slaveId);
        for (int i = 0; i < data.length; i += 2) {
            int val = (data[i] & 0xFF) << 8;
            if (i + 1 < data.length) {
                val |= (data[i + 1] & 0xFF);
            }

            map.put(startAddress + i / 2, val);
        }
    }

    /**
     * 读取单个寄存器
     */
    public static int read(int slaveId, int address) {
        return getRegisterMap(slaveId).getOrDefault(address, 0);
    }

    /**
     * 读取多个寄存器，返回byte[]
     */
    public static byte[] read(int slaveId, int startAddress, int quantity) {
        ByteBuf buf = Unpooled.buffer(quantity * 2);
        Map<Integer, Integer> map = getRegisterMap(slaveId);
        for (int i = 0; i < quantity; i++) {
            buf.writeShort(map.getOrDefault(startAddress + i, 0));
        }
        byte[] result = new byte[buf.readableBytes()];
        buf.readBytes(result);
        buf.release();
        return result;
    }
}
